/*
 * Copyright (C) 2019 Adaptech s.r.o., Robert Pösel
 * Copyright (C) 2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.googlecode.leptonica.android;

/**
 * Image scaling methods.
 *
 * @author alanv@google.com (Alan Viverette)
 */
public class Scale {
	static {
		System.loadLibrary("jpeg");
		System.loadLibrary("pngx");
		System.loadLibrary("leptonica");
	}

	public enum ScaleType {
		/* Scale in X and Y independently, so that src matches dst exactly. */
		FILL,

		/*
		 * Compute a scale that will maintain the original src aspect ratio, but
		 * will also ensure that src fits entirely inside dst. May shrink or
		 * expand src to fit dst.
		 */
		FIT,

		/*
		 * Compute a scale that will maintain the original src aspect ratio, but
		 * will also ensure that src fits entirely inside dst. May shrink src to
		 * fit dst, but will not expand it.
		 */
		FIT_SHRINK,
	}

	/**
	 * Scales the Pix to a specified width and height using a specified scaling
	 * type (fill, stretch, etc.). Returns a scaled image or a clone of the Pix
	 * if no scaling is required.
	 *
	 * @param pixs   Source pix image
	 * @param width  The desired width to scale to
	 * @param height The desired height to scale to
	 * @param type   The desired scaling type
	 * @return a scaled image or a clone of the Pix if no scaling is required
	 */
	public static Pix scaleToSize(Pix pixs, int width, int height, ScaleType type) {
		if (pixs == null)
			throw new IllegalArgumentException("Source pix must be non-null");

		int pixWidth = pixs.getWidth();
		int pixHeight = pixs.getHeight();

		float scaleX = width / (float) pixWidth;
		float scaleY = height / (float) pixHeight;

		switch (type) {
			case FILL:
				// Retains default scaleX and scaleY values
				break;
			case FIT:
				scaleX = Math.min(scaleX, scaleY);
				//noinspection SuspiciousNameCombination
				scaleY = scaleX;
				break;
			case FIT_SHRINK:
				scaleX = Math.min(1.0f, Math.min(scaleX, scaleY));
				//noinspection SuspiciousNameCombination
				scaleY = scaleX;
				break;
		}

		return scale(pixs, scaleX, scaleY);
	}

	/**
	 * Scales the Pix to specified scale. If no scaling is required, returns a
	 * clone of the source Pix.
	 *
	 * @param pixs  the source Pix
	 * @param scale dimension scaling factor
	 * @return a Pix scaled according to the supplied factors
	 */
	public static Pix scale(Pix pixs, float scale) {
		return scale(pixs, scale, scale);
	}

	/**
	 * Scales the Pix to the specified scale without sharpening.
	 *
	 * @param pixs  the source Pix (1, 2, 4, 8, 16 and 32 bpp)
	 * @param scale scaling factor for both X and Y
	 * @return a Pix scaled while maintaining its aspect ratio
	 */
	public static Pix scaleWithoutSharpening(Pix pixs, float scale) {
		if (pixs == null)
			throw new IllegalArgumentException("Source pix must be non-null");
		if (scale <= 0.0f)
			throw new IllegalArgumentException("Scaling factor must be positive");

		return new Pix(nativeScaleGeneral(pixs.getNativePix(), scale, scale,
				0f, 0));
	}

	/**
	 * Scales the Pix to specified x and y scale. If no scaling is required,
	 * returns a clone of the source Pix.
	 *
	 * @param pixs   the source Pix
	 * @param scaleX x-dimension (width) scaling factor
	 * @param scaleY y-dimension (height) scaling factor
	 * @return a Pix scaled according to the supplied factors
	 */
	public static Pix scale(Pix pixs, float scaleX, float scaleY) {
		if (pixs == null)
			throw new IllegalArgumentException("Source pix must be non-null");
		if (scaleX <= 0.0f)
			throw new IllegalArgumentException("X scaling factor must be positive");
		if (scaleY <= 0.0f)
			throw new IllegalArgumentException("Y scaling factor must be positive");

		long nativePix = nativeScale(pixs.getNativePix(), scaleX, scaleY);

		if (nativePix == 0)
			throw new RuntimeException("Failed to natively scale pix");

		return new Pix(nativePix);
	}

	// ***************
	// * NATIVE CODE *
	// ***************

	private static native long nativeScale(long nativePix, float scaleX, float scaleY);

	private static native long nativeScaleGeneral(long nativePix, float scaleX, float scaleY, float sharpfract, int sharpwidth);

}
